﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;

namespace IdmlSharp
{

	/// <summary>
	/// 
	/// </summary>
	public class IdmlReader : IDisposable
	{

		#region Fields

		private string _path;

		private Document _currentDocument;
		private Spread _currentSpread;
		private Rectangle _currentRectangle;
		private Image _currentImage;
		private Link _currentLink;
		private TextFrame _currentTextFrame;
		private Story _currentStory;
		private ParagraphStyleRange _currentParagraphStyleRange;
		private CharacterStyleRange _currentCharacterStyleRange;

		#endregion

		#region Constrcutors

		/// <summary>
		/// 
		/// </summary>
		/// <param name="docPath"></param>
		protected IdmlReader(string path)
		{
			this._path = path;
		}

		#endregion

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		protected Stream GetResource(string path)
		{
			string file = Path.GetFileName(path);
			string dir = Path.GetDirectoryName(path);
			Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(this._path);
			foreach (Ionic.Zip.ZipEntry entry in zip.SelectEntries(file, dir))
			{
				return entry.OpenReader();
			}
			return null;
		}

		/// <summary>
		/// 
		/// </summary>
		public static Idml Read(string idmlPath)
		{
			IdmlReader instance = new IdmlReader(idmlPath);
			Idml model = new Idml();
			instance.Read(model);
			return model;
		}

		/// <summary>
		/// 
		/// </summary>
		internal void Read(Idml model)
		{
			XmlReadingEventHandler handler = new XmlReadingEventHandler();
			handler.ElementStart += delegate(object sender, XmlReadingEventArgs e)
			{
				XmlTextReader reader = e.XmlTextReader;
				if ("Document".Equals(reader.Name, StringComparison.OrdinalIgnoreCase))
				{
					model.Document = this.CreateDocuemt(reader);
				}
				/* Spread */ 
				if ("idPkg:Spread".Equals(reader.Name, StringComparison.OrdinalIgnoreCase))
				{
					string src = reader.GetAttribute("src");
					if (!string.IsNullOrEmpty(src)) IdPkgSpreadReader.Read(this.GetResource(src), handler);
				}
				if ("Spread".Equals(reader.Name, StringComparison.OrdinalIgnoreCase))
				{
					this.AddSpread(reader);
				}
				if ("Rectangle".Equals(reader.Name, StringComparison.OrdinalIgnoreCase))
				{
					this.AddRectangle(reader);
				}
				if ("Image".Equals(reader.Name, StringComparison.OrdinalIgnoreCase))
				{
					this.AddImage(reader);
				}
				if ("Link".Equals(reader.Name, StringComparison.OrdinalIgnoreCase))
				{
					this.AddLink(reader);
				}
				if ("TextFrame".Equals(reader.Name, StringComparison.OrdinalIgnoreCase))
				{
					this.AddTextFrame(reader);
				}
				/* Story */
				if ("idPkg:Story".Equals(reader.Name, StringComparison.OrdinalIgnoreCase))
				{
					string src = reader.GetAttribute("src");
					if (!string.IsNullOrEmpty(src)) IdPkgStoryReader.Read(this.GetResource(src), handler);
				}
				if ("Story".Equals(reader.Name, StringComparison.OrdinalIgnoreCase))
				{
					this.AddStory(reader);
				}
				if ("ParagraphStyleRange".Equals(reader.Name, StringComparison.OrdinalIgnoreCase))
				{
					this.AddParagraphStyleRange(reader);
				}
				if ("CharacterStyleRange".Equals(reader.Name, StringComparison.OrdinalIgnoreCase))
				{
					this.AddCharacterStyleRange(reader);
				}
				if ("Content".Equals(reader.Name, StringComparison.OrdinalIgnoreCase))
				{
					this.AddContent(reader);
				}
			};
			DesignMapReader.Read(this.GetResource("designmap.xml"), handler);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="reader"></param>
		/// <returns></returns>
		protected Document CreateDocuemt(XmlTextReader reader)
		{
			this._currentDocument = new Document();
			return this._currentDocument;
		}

		protected Spread AddSpread(XmlTextReader reader)
		{
			this._currentSpread = new Spread(reader.GetAttribute("Self"));
			this._currentDocument.AddSpread(this._currentSpread.Self, this._currentSpread);
			return this._currentSpread;
		}

		protected Rectangle AddRectangle(XmlTextReader reader)
		{
			this._currentRectangle = new Rectangle(reader.GetAttribute("Self"));
			this._currentSpread.AddRectangle(this._currentRectangle.Self, this._currentRectangle);
			return this._currentRectangle;
		}


		protected Image AddImage(XmlTextReader reader)
		{
			this._currentImage = new Image(reader.GetAttribute("Self"));
			this._currentRectangle.AddImage(this._currentImage.Self, this._currentImage);
			return this._currentImage;
		}

		protected Link AddLink(XmlTextReader reader)
		{
			this._currentLink = new Link(reader.GetAttribute("Self"));
			this._currentLink.LinkResourceURI = reader.GetAttribute("LinkResourceURI");
			this._currentImage.AddLink(this._currentLink.Self, this._currentLink);
			return this._currentLink;
		}

		protected TextFrame AddTextFrame(XmlTextReader reader)
		{
			this._currentTextFrame = new TextFrame(reader.GetAttribute("Self"));
			this._currentSpread.AddTextFrame(this._currentTextFrame.Self, this._currentTextFrame);
			this._currentTextFrame._parentStoryId = reader.GetAttribute("ParentStory");
			return this._currentTextFrame;
		}

		protected Story AddStory(XmlTextReader reader)
		{
			this._currentStory = new Story(reader.GetAttribute("Self"));
			this._currentDocument.AddStory(this._currentStory.Self, this._currentStory);
			TextFrame textFrame = this.FindTextFrameByParentStoryId(this._currentStory.Self);
			if (textFrame != null) textFrame.SetParentStory(this._currentStory);
			return this._currentStory;
		}

		

		protected ParagraphStyleRange AddParagraphStyleRange(XmlTextReader reader)
		{
			this._currentParagraphStyleRange = new ParagraphStyleRange();
			this._currentStory.ParagraphStyleRange = this._currentParagraphStyleRange;
			return this._currentParagraphStyleRange;
		}

		protected CharacterStyleRange AddCharacterStyleRange(XmlTextReader reader)
		{
			this._currentCharacterStyleRange = new CharacterStyleRange();
			this._currentParagraphStyleRange.CharacterStyleRange = this._currentCharacterStyleRange;
			return this._currentCharacterStyleRange;
		}

		protected string AddContent(XmlTextReader reader)
		{
			this._currentCharacterStyleRange.Content= reader.ReadInnerXml();
			return this._currentCharacterStyleRange.Content;
		}

		protected TextFrame FindTextFrameByParentStoryId(string id)
		{
			foreach (Spread spread in this._currentDocument.Spreads.Values)
			{
				foreach (TextFrame textFrame in spread.TextFrames.Values)
				{
					if (textFrame._parentStoryId.Equals(id))
					{
						return textFrame;
					}
				}
			}
			return null;
		}

		#region IDisposable メンバー

		public void Dispose()
		{
		}

		#endregion

	}

}
